春节Vue-2.6.0发布后,对slot插槽进行了一定的优化,那么对于插槽,你真正的了解吗?以下是我使用中总结的拙见,欢迎批评指正+++++
最近在做业务组件的时候,用到三种slot,被叫做”默认插槽“,”具名插槽“,”作用域插槽“。
默认插槽
子组件
<a v-bind:href="url" class="nav-link">
<slot>content</slot>
</a>
父组件
<navigation-link url="/profile">
Your Profile
</navigation-link>
如果父组件为这个插槽提供了内容Your Profile,则默认的内容content会被替换掉。
具名插槽
如果子组件中的多个位置都需要父组件塞进不同的内容时,你需要使用具名插槽。
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot name-"main"></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
子组件在header main footer三处需要塞入不同的内容,在父组件的 <template> 元素上使用 slot特性:
<base-layout>
<template slot="header">
<h1>Here might be a page title</h1>
</template>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
<template slot="footer">
<p>Here's some contact info</p>
</template>
</base-layout>
看起来具名插槽能解决大部分的问题了,但是,在这种情况面前使用具名插槽会报错:
<div v-for="(item, index) in resultList" :key="index">
<div class="list-content">
<p class="content" v-html="item.content"/>
<slot name="content"></slot>
</div>
</div>
当使用v-for迭代,同一具名插槽重复出现的时候,浏览器就会报错
这时我们不得不使用作用域插槽
作用域插槽
在 <template> 上使用特殊的 slot-scope 特性,可以接收传递给插槽的 prop
子组件内两处地方放置两处插槽
<!--位置1-->
<slot name="tips" :tips="item.access"></slot>
<!--位置2-->
<slot name="content" :content="item.content"></slot>
父组件-使用时,slot=name 具名,调用scope.[name]
<template slot="tips" slot-scope="scope">
<span class="item-header-state" v-if="scope.tips === true"><i class="el-icon-check" />已认证</span>
</template>
<template slot="content" slot-scope="scope">
<el-tag
v-for="(tag, index) in scope.content.labels"
:key="index"
closable
type="info"
size="small"
:disable-transitions="false"
@close="handleCloseTag(tag, scope.content)">
{{tag.label}}
</el-tag>
</template>
But 自 2.6.0 起以上被废弃。新推荐的语法请查阅这里。
【以下为引用内容】
插槽和具名插槽
父组件以另外一种方式(不是通过常规的 Props 属性传递机制)向子组件传递信息。我发现把这种方法同常规的 HTML 元素联系起来很有帮助。
比如说 HTML 标签。
<a href=”/sometarget">This is a link</a>
如果这是在 Vue 环境中并且 <a>
是你的组件,那么你需要发送“This is a link”信息到‘a’组件里面,然后它将被渲染成为一个超链接,而“This is a link”就是这个链接的文本。
让我们定义一个子组件来展示它的机制是怎样的:
<template>
<div>
<slot></slot>
</div>
</template>
然后在父组件我们这么做:
<template>
<div>
<child-component>This is from outside</child-component>
</div>
</template>
这时候屏幕上呈现的就应该和你预期的一样就是“This is from outside”,但这是由子组件所渲染出来的。
我们还可以给子组件添加默认的信息,以免到时候这里出现什么都没有传入的情况,就像这样子:
<template>
<div>
<slot>Some default message</slot>
</div>
</template>
然后如果我们像这样子创建我们的子组件:
<child-component>
</child-component>
我们可以看到屏幕上会呈现“Some default message”。
具名插槽和常规插槽非常类似,唯一的差别就是你可以在你的目标组件多个位置传入你的文本。
我们把子组件升级一下,让它有多个具名插槽
<template>
<div>
<slot>Some default message</slot>
<br/>
<slot _name_="top"></slot>
<br/>
<slot _name_="bottom"></slot>
</div>
</template>
这样,在我们的子组件中就有了三个插槽。其中 top 和 bottom 插槽是具名插槽。
让我们更新父组件以使用它。
<child-component _v-slot:top_>
Hello there!
</child-component>
注意 —— 我们在这里使用新的 Vue 2.6 语法来指定我们想要定位的插槽:v-slot:theName
。
你现在认为会在屏幕上看到什么呢?如果你说是“Hello Top!”,那么你就只说对了一部分。
因为我没有为没有具名的插槽赋予任何值,我们因此也还会得到默认值。所以我们真正会看到的是:
Some default message
Hello There!
其实真正意义上没有具名的插槽是被当作‘default’,所以你还可以这么做:
<child-component _v-slot:default_>
Hello There!
</child-component>
现在我们就只会看到:
Hello There!
因为我们已经提供了值给默认(也就是未具名)插槽,因此具名插槽‘top’和‘bottom’也都没有默认值。
你发送的并不一定只是文本,还可以是其他组件或者 HTML。你可以发送任意你想展示的内容。
作用域插槽
我认为插槽和具名插槽相对简单,一旦你稍微玩玩就可以掌握。可另一方面,作用域插槽虽然名字相似但又有些不同之处。
我倾向于认为作用域插槽有点像一个放映机(或者是一个我欧洲朋友的投影仪)。以下是原因。
子组件中的作用域插槽可以为父组件中的插槽的显示提供数据。这就像一个人带着放映机站在你的子组件里面,然后在父组件的墙上让一些图像发光。
这有一个例子。在子组件中我们像这样设置了一个插槽:
<template>
<div>
<slot _name_="top" _:myUser_="user"></slot>
<br/>
<slot _name_="bottom"></slot>
<br/>
</div>
</template>
<script>
data() {
_return_ {
user: "Ross"
}
}
</script>
注意到我们的具名插槽‘top’现在有了一个名为‘myUser’的属性,然后我们绑定了一个动态的值在‘user’中。
在我们的父组件中就像这样子设置子组件:
<div>
<child-component _v-slot:top_="slotProps">{{ slotProps }}</child-component>
</div>
我们在屏幕上看到的就是这样子:
{ “myUser”: “Ross” }
还是使用放映机的类比,我们的子组件通过 myUser 对象将其用户字符串的值传递给父组件。它在父组件上投射到的墙就被称为‘slotProps’。
我知道这不是一个完美的类比,但当我第一次尝试理解这个机制的时候,它帮助我以这种方式思考。
Vue 的文档非常好,而且我也已经看到了一些其他关于作用域插槽工作机制的说明。但很多人采取的方法似乎是将父组件中的所有或部分属性命名为与子组件相同,我认为这会使得数据很难被追踪。
在父组件中使用 ES6 解构,我们这样子写还可以将特定 user 对象从插槽属性(你可以随便怎么称呼它)解脱出来:
<child-component _v-slot:top_="{myUser}">{{ myUser }}</child-component>
或者甚至就只是在父组件中给它一个新的名字:
<child-component _v-slot:top_="{myUser: aFancyName}">{{ aFancyName }}</child-component>
所有都是通过 ES6 解构,与 Vue 本身并没有什么关系。
如果你正开始使用 Vue 和插槽,希望这可以让你起步并解决一些棘手的问题。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。